//
//  Index.swift
//  cnswift-demo
//
//  Created by YangWei on 2020/12/31.
//  Copyright © 2020 YangWei. All rights reserved.
//

import UIKit

/// 1 下标语法
/// 对应整数的乘法表（演示了只读下标的实现）
struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}

/// 3 下标选项
/// 定义一个 Matrix 结构体，表示一个 Double 类型的二维矩阵。
/// Matrix 结构体的下标接受两个整型参数
struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]
    
    // 一个接受两个入参的构造方法，入参分别是 rows 和 columns，创建了一个足够容纳 rows * columns 个 Double 类型的值的数组
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        // 通过传入数组长度和初始值 0.0 到数组的构造器，将矩阵中每个位置的值初始化为 0.0
        grid = Array(repeating: 0.0, count: rows * columns)
    }
    
    // 便利方法，用来检查入参 row 和 column 的值是否在矩阵范围内
    func indexIsValid(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    
    subscript(row: Int, column: Int) -> Double {
        // getter 和 setter 中都含有断言，用来检查下标入参 row 和 column 的值是否有效。
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

/// 4 类型下标
/// 定义一个类型下标
enum PlanetV3: Int {
    /* 八大行星： 水星、金星、地球、火星、木星、土星、天王星、海王星 */
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> PlanetV3 {
        return PlanetV3(rawValue: n)!
    }
}

class Subscripts: SWDBaseObject {
    
    class func run() {
        
        let subscripts = Subscripts()
        
        // 1
        subscripts.subscriptSyntax()
        
        // 2
        subscripts.subscriptUsage()
        
        // 3
        subscripts.subscriptOptions()
        
        // 4
        subscripts.typeSubscripts()
    }
    
    /// 1 下标语法
    func subscriptSyntax() {
        let title = "1 下标语法";
        printStartLine(title)
        
        // 表示整数 3 的乘法表，通过下标访问 threeTimesTable 实例
        let threeTimesTable = TimesTable(multiplier: 3)
        print("six times three is \(threeTimesTable[6])")
        // 打印“six times three is 18”
        
        printEndLine(title)
    }
    
    /// 2 下标用法
    func subscriptUsage() {
        let title = "2 下标用法";
        printStartLine(title)
        
        // 定义一个名为 numberOfLegs 的变量，并用一个包含三对键值的字典字面量初始化它
        // numberOfLegs 字典的类型被推断为 [String: Int]。
        // 通过下标将 String 类型的键 bird 和 Int 类型的值 2 添加到字典中
        var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
        numberOfLegs["bird"] = 2
        print(numberOfLegs)
        
        printEndLine(title)
    }
    
    /// 3 下标选项
    func subscriptOptions() {
        let title = "3 下标选项";
        printStartLine(title)
        
        // 通过传入合适的 row 和 column 数值来构造一个新的 Matrix 实例：
        var matrix = Matrix(rows: 2, columns: 2)
        print(matrix)
        
        // 将 row 和 column 的值传入下标来为矩阵设值，下标的入参使用逗号分隔：
        matrix[0, 1] = 1.5
        matrix[1, 0] = 3.2
        print(matrix)
        
        // 断言在下标越界时触发：
//        let someValue = matrix[2, 2]
        // 断言将会触发，因为 [2, 2] 已经超过了 matrix 的范围
//        print(someValue)
        
        printEndLine(title)
    }
    
    /// 4 类型下标
    func typeSubscripts() {
        let title = "4 类型下标";
        printStartLine(title)
        
        // 展示调用一个类型下标
        let mars = PlanetV3[4]
        print(mars)
        
        
        printEndLine(title)
    }
}
